package com.eliaukjq.jihe;

import javax.swing.*;
import java.lang.annotation.ElementType;

/**
 * @Author : 佩萁
 * Description :
 * @Create : 2024/7/16 - 15:33
 */

/**
 * demo03 类用于演示如何创建和打印单链表。
 */
public class demo03 {
    /**
     * 程序入口。
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 创建链表节点
        LisNode node1 = new LisNode(1);
        LisNode node2 = new LisNode(2);
        LisNode node3 = new LisNode(3);
        LisNode node4 = new LisNode(4);
        LisNode node5 = new LisNode(5);
        // 链接节点
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        // 打印链表的头节点
        System.out.println(node1);
        // 打印整个链表
        printList(node1);

        //插入结点
        LisNode insertNode = new LisNode(9);
        insertNode(node5, insertNode);
        printList(node1);

        //删除结点
        deleteNode(node5);
        printList(node1);

        //寻找索引结点
        LisNode access = access(node1, 4);
        System.out.println(access);
        printList(access);

        //查找结点,在链表中查找首个值为target的结点索引
        Integer index = findNode(node1, 6);
        System.out.println(index);
    }

    /**
     * 打印单链表的所有节点值。
     *
     * @param head 链表的头节点
     */
    //定义链表打印方法
    public static void printList(LisNode head) {
        LisNode current = head;
        // 遍历链表直到尾节点
        while (!(current == null)) {
            System.out.print(current.val);
            System.out.print("-->");
            current = current.next;
        }
        System.out.println("null");
    }

    //插入结点

    /**
     * 在给定的最长递增子序列(LIS)节点之后插入一个新节点。
     * 此函数不改变原有LIS的长度，只是在特定位置插入一个新节点。
     *
     * @param lisNode    当前LIS的最后一个节点，新节点将插入到这个节点之后。
     * @param insertNode 待插入的新节点。
     */
    public static void insertNode(LisNode lisNode, LisNode insertNode) {
        // 将新节点的next指针指向当前LIS节点的下一个节点，为插入新节点做准备。
        insertNode.next = lisNode.next;
        // 将当前LIS节点的next指针指向新节点，完成插入操作。
        lisNode.next = insertNode;
    }

    //删除结点

    /**
     * 删除单链表中的指定节点。
     * 该方法接收一个链表节点作为参数，并删除该节点的下一个节点。
     * 如果传入的节点是链表的最后一个节点或者为空，则不进行任何操作。
     *
     * @param lisNode 链表节点，该节点可能被删除。
     */
    public static void deleteNode(LisNode lisNode) {
        // 检查当前节点是否是链表的最后一个节点，如果是，则不进行删除操作
        if (lisNode.next == null)
            return;
        // 跳过当前节点的下一个节点，实现删除操作
        lisNode.next = lisNode.next.next;
    }

    //访问索引为index的结点

    /**
     * 根据索引访问LisNode链表中的节点。
     * <p>
     * 此函数接收一个链表的头节点和一个索引，然后遍历链表直到达到指定的索引位置。
     * 如果索引超出链表长度或者链表为空，则返回null。
     * 否则，返回索引对应的链表节点。
     *
     * @param head  链表的头节点。
     * @param index 需要访问的节点的索引。
     * @return 返回指定索引位置的节点，如果不存在则返回null。
     */
    static LisNode access(LisNode head, int index) {
        // 从头节点开始遍历链表
        for (int i = 0; i < index; i++) {
            // 如果链表为空，直接返回null
            if (head == null)
                return null;
            // 移动到下一个节点
            head = head.next;
        }
        // 返回遍历到的节点
        return head;
    }

    //查找结点,在链表中查找首个值为target的结点索引
    /**
     * 在长度递增的链表中查找目标节点的索引。
     * 该方法用于一个特殊的链表，这个链表是按照值的非递减顺序排列的。
     *
     * @param head 链表的头节点，不为null。
     * @param target 要查找的目标值。
     * @return 目标值在链表中的索引，如果不存在则返回null。
     */
    static Integer findNode(LisNode head, int target) {
        /* 初始化索引为0，用于记录目标节点的索引位置 */
        int index = 0;
        /* 当前节点指针，用于遍历链表 */
        LisNode current = head;
        /* 遍历链表直到找到目标值或链表结束 */
        while (current.val != target) {
            /* 如果当前节点的下一个节点为空，说明目标值不在链表中 */
            if (current.next == null){
                return null;
            }
            /* 更新索引，准备访问下一个节点 */
            index = index + 1;
            /* 移动到下一个节点 */
            current = current.next;
        }
        /* 如果找到目标值，返回目标值的索引 */
        return index;
    }
}

/**
 * LisNode 类表示单链表的节点。
 */
class LisNode {
    int val; // 节点的值
    LisNode next; // 指向下一个节点的指针

    /**
     * 构造函数初始化节点的值和下一个节点的指针。
     *
     * @param val 节点的初始值
     */
    public LisNode(int val) {
        this.val = val;
        this.next = null;//默认为null，这样在指定时，到尾结点就为null
    }
}
